/*
 * @Author: gggg 1263457581@qq.com
 * @Date: 2025-06-06 14:33:02
 * @LastEditors: gggg 1263457581@qq.com
 * @LastEditTime: 2025-06-06 14:53:42
 * @FilePath: /algorithm-and-data-struct/pool/BlockingQueue.cpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */


#include <iostream>
#include <queue>

template <typename T>
class BlockingQueue
{
public:
    explicit BlockingQueue(){}
    
    ~BlockingQueue()
    {
        while (!queue.empty())
        {
            T item = queue.front();
            queue.pop();
        }    
    }
    
    void push(const T& item)
    {
        std::unique_lock<std::mutex> lock(mutex);
        cv_not_full.wait(lock, [this](){return queue.size() < max_size;});
        queue.push(item);
        cv_not_empty.notify_one();
    }
    
    T pop()
    {
        std::unique_lock<std::mutex> lock(mutex); 
        cv_not_empty.wait(lock, [this](){return !queue.empty();});
        T item = queue.front();
        queue.pop();
        cv_not_full.notify_one();  
        return item; 
    }

private:
    std::queue<T> queue;
    std::mutex mutex;
    std::condition_variable cv_not_full;
    std::condition_variable cv_not_empty;
    int max_size;
}

int main()
{
    BlockingQueue<int> queue(5);

    std::thread t1([&queue](){
        for (int i = 0; i < 10; i++)
        {
            queue.push(i);
            std::cout << "push " << i << std::endl;
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }
    });

    std::thread t2([&queue](){
        for (int i = 0; i < 10; i++)
        {
            int item = queue.pop();
            std::cout << "pop " << item << std::endl;
            std::this_thread::sleep_for(std::chrono::milliseconds(200));
        }
    }); 

    t1.join();
    t2.join();
}